iT邦幫忙

0

day27 Console Summary 掃描總結報告

  • 分享至 

  • xImage
  •  

今天嘗試把之前的「Port Scanner 專案」加上 Console Summary(掃描總結報告)。
掃描完所有的 port,不只是一行一行輸出結果,還會在最後整理:
Host (主機名稱)
掃描的 Port 範圍
總共幾個 Port
有幾個開啟 (OPEN)
有幾個關閉 (CLOSED)
花了多少時間 (Elapsed)
額外還做了一個 漂亮的表格輸出(類似 ASCII table)。

package day1.day1;

import java.util.;
import java.util.concurrent.
;
import java.net.;
import java.io.
;

public class Day27Demo {
static class Result {
final int port;
final String status;
Result(int port, String status) { this.port = port; this.status = status; }
}
private static String checkPort(String host, int port,int timeoutMs) {
try (Socket socket = new Socket()){
socket.connect(new InetSocketAddress(host,port),timeoutMs);
return "OPEN";
}catch (IOException e){
return "CLOSED";
}
}
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.print("Host(e.g. localhost): ");

    String host = sc.nextLine().trim();
    System.out.print("START port:");

    int start= Integer.parseInt(sc.nextLine().trim());
    System.out.print("END port:");

    int end= Integer.parseInt(sc.nextLine().trim());
    System.out.print("TIMEOUT ms (e.g. 200): ");
    int timeoutMs = Integer.parseInt(sc.nextLine().trim());

    final  int total = Math.max(0, end - start + 1);
    if (total == 0) {
        System.out.println("No ports to scan."); return; }
    ExecutorService executor = Executors.newFixedThreadPool(10);
    List<Result> results = Collections.synchronizedList(new ArrayList<>());

    long startTime = System.currentTimeMillis();
    CountDownLatch latch = new CountDownLatch(total);

    for (int p = start; p<=end; p++) {final int port = p;
        executor.execute(() -> {
            String status = checkPort(host, port, timeoutMs);
            results.add(new Result(port, status));
            System.out.printf("\rScanned port %d/%d", (total - latch.getCount() + 1), total);
            latch.countDown();
        });
    }

    latch.await();
    executor.shutdown();

    long elapsed = System.currentTimeMillis() - startTime;

    long openCount = results.stream().filter(r -> r.status.equals("OPEN")).count();
    long closedCount = total-openCount;
    System.out.println("\n\n===== Scan Summary =====");
    System.out.printf("Host       : %s%n", host);
    System.out.printf("Ports      : %d - %d (total %d)%n", start, end, total);
    System.out.printf("OPEN       : %d%n", openCount);
    System.out.printf("CLOSED     : %d%n", closedCount);
    System.out.printf("Elapsed    : %.2f seconds%n", elapsed / 1000.0);
    System.out.println("========================");


    // 如果想要漂亮一點的表格:
    System.out.println("\nPort Status Table:");
    System.out.println("+-------+--------+");
    System.out.println("| Port  | Status |");
    System.out.println("+-------+--------+");
    for (Result r : results) {
        System.out.printf("| %-5d | %-6s |%n", r.port, r.status);
    }
    System.out.println("+-------+--------+");
}

}

https://ithelp.ithome.com.tw/upload/images/20251018/20179429MPbfOcuwbt.png

練習後學到:
CountDownLatch:
它是 Java 並發工具(java.util.concurrent) 的一個類別。
你可以把它想成「一個倒數計時器」或者「一扇門,有很多把鎖」。
它的作用是:等到某些工作都完成之後,再繼續往下跑程式。

new CountDownLatch(total);
這行程式的意思是:
「建立一個倒數計數器,初始值是 total。」
total 通常代表 -> 有多少個任務/工作要做。
每次一個工作完成時,會呼叫 latch.countDown(); → 把計數器減 1。
當計數器變成 0,表示所有工作都完成了,等待的程式就會繼續往下執行。

System.out.printf("\rScanned port %d/%d", (total - latch.getCount() + 1), total);
latch.countDown();

\r 叫做 Carriage Return,意思是「把游標移到這一行的最前面」。
它不會換行,只是回到行首。
這樣可以做到「在同一行更新進度」,不會一直印很多行。

(total - latch.getCount() + 1)
這一段是算「目前做到第幾個」。
latch.getCount() → 目前倒數計時器還剩多少(例如還有 9 個工作沒做)。
total - latch.getCount() → 已經完成了多少個。
+1 → 因為正在處理當前這個任務,所以要加回去。
假設 total = 100,latch.getCount() = 90(還有 90 個沒做)
計算 → 100 - 90 + 1 = 11
表示「現在是第 11 個任務」。

latch.countDown();
這是把倒數計時器 -1,代表「這個任務完成了」。
如果原本是 100 → 變成 99。
當最後減到 0 的時候,所有等待 latch.await() 的程式就會繼續執行。

學到不是只會「功能跑出來就好」,還要會做 總結 / 報告,才能讓使用者更快理解結果。美化 Console 輸出很重要,因為 CLI 程式通常給人第一印象就是「排版好不好讀」。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言